package ac.il.technion.cs236369.hw5.core.xslt;

import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

import ac.il.technion.cs236369.hw5.core.entities.XsltStorage;
import ac.il.technion.cs236369.hw5.core.utils.OperationResult;

import com.google.gson.Gson;


/**
 * @author c0rwin
 *
 */
public enum XsltStorageOperation {
	
	XSLT_INSERT( "xslt_insert") {
		private ThreadLocal<Integer> id = new ThreadLocal<Integer>( );
		public XsltStorageOperation execute( HttpServletRequest request) {
			EntityManager manager = emf.createEntityManager( );
			EntityTransaction transaction = manager.getTransaction( );
			final XsltStorage storage = new XsltStorage( );
			transaction.begin( );
			Map< String, String> parameters = XsltStorageParameters.getParameters( request);
			parameters.put( "postedBy", request.getUserPrincipal( ).getName( ));
			try {
				for ( XsltStorageParameters $ : XsltStorageParameters.values( )) {
					$.saveParameter( storage, parameters, manager);
				}
				manager.persist( storage);
				transaction.commit( );
				status.set( OperationResult.SUCCESS);
				id.set(  storage.getId( ));
			} catch ( Exception e) {
				logger.error( e.getMessage( ));
				transaction.rollback( );
				status.set( OperationResult.ERROR);
			} finally {
				manager.close( );
			}
			return this;
		}
		
		public XsltStorageOperation result( HttpServletResponse response) {
			try {
				switch( status.get( )) {
					case SUCCESS : {
						response.getWriter( ).println( id.get( ));
						break;
					}
					case ERROR : {
						response.getWriter( ).println( "ERROR");
						break;
					}
				}
			} catch (IOException e) {
				logger.error( e.getMessage( ));
			}
			return this;
		}
	},
	XSLT_DELETE( "xslt_delete") {
		private ThreadLocal<String> id = new ThreadLocal<String>( );
		public XsltStorageOperation execute( HttpServletRequest request) {
			id.set( request.getParameter( XsltStorageParameters.XSLT_ID.toString( )));
			if ( id.get( ) == null || id.get( ).length( ) == 0) {
				status.set( OperationResult.ERROR);
				logger.warn( "Please provide with correct id.");
			}
			EntityManager manager = emf.createEntityManager( );
			EntityTransaction transaction = manager.getTransaction( );
			transaction.begin( );
			try {
				manager.createQuery( "DELETE FROM XsltStorage x WHERE x.id = :id")
					.setParameter( "id", Integer.valueOf( id.get( ))).executeUpdate( );
				transaction.commit( );
				status.set( OperationResult.SUCCESS);
			} catch ( Exception e) {
				logger.error( e.getMessage( ));
				transaction.rollback( );
				status.set( OperationResult.ERROR);
			}
			return this;
		}
		
		public XsltStorageOperation result( HttpServletResponse response) {
			try {
				switch( status.get( )) {
					case SUCCESS : {
						response.getWriter( ).println( id.get( ));
						break;
					}
					case ERROR : {
						response.getWriter( ).println( "ERROR");
						break;
					}
				}
			} catch (IOException e) {
				logger.error( e.getMessage( ));
			}
			return this;
		}
	},
	XSLT_GET( "xslt_get_content") {
		private ThreadLocal<String> content = new ThreadLocal<String>( );
		public XsltStorageOperation execute( HttpServletRequest request) {
			EntityManager manager = emf.createEntityManager( );
			String xsltId = request.getParameter( XsltStorageParameters.XSLT_ID.toString( ));
			if ( xsltId == null || xsltId.length( ) == 0) {
				status.set( OperationResult.ERROR);
				return this;
			}
			try {
				final XsltStorage storage = manager.find( XsltStorage.class, Integer.valueOf( xsltId));
				if ( storage == null) {
					status.set( OperationResult.ERROR);
					return this;
				}
				content.set( storage.getContent( )); 
			} finally {
				manager.close( );
			}
			status.set( OperationResult.SUCCESS);
			return this;
		}
		
		public XsltStorageOperation result( HttpServletResponse response) {
			try {
				switch( status.get( )) {
					case SUCCESS : {
						response.setContentType( "application/xml");
						response.getWriter( ).println( content.get( ));
						break;
					}
					case ERROR : {
						response.getWriter( ).println( "ERROR");
						break;
					}
				}
			} catch (IOException e) {
				logger.error( e.getMessage( ));
			}
			return this;
		}
	},
	XSLT_LIST_ALL( "xslt_list_all") {
		private ThreadLocal< Collection<XsltStorage>> templates = new ThreadLocal< Collection<XsltStorage>>( );
		public XsltStorageOperation execute( HttpServletRequest request) {
			EntityManager manager = emf.createEntityManager( );
			templates.set( manager.createQuery( "SELECT s FROM XsltStorage s", XsltStorage.class).getResultList( ));
			return this;
		}
		
		public XsltStorageOperation result( HttpServletResponse response) {
			Gson gson = new Gson( );
			XsltStorageItems storageItems = new XsltStorageItems( );
			for( XsltStorage $ : templates.get( )) {
				XsltStorageEnvelope item = new XsltStorageEnvelope( $.getId( ), $.getName( ), $.getType( ), $.getPostedBy( ).getLoginName( ));
				storageItems.getItems( ).add( item);
			}
			try {
				response.getWriter( ).println( gson.toJson( storageItems));
			} catch (IOException e) {
				logger.error( e.getMessage( ));
			}
			return this;
		}
	},
	UNDEFINED( "undefined") {
		public XsltStorageOperation execute( HttpServletRequest request) {
			logger.warn( "XsltOperation is not defined.");
			return this;
		}
		
		public XsltStorageOperation result( HttpServletResponse response) {
			try {
				response.getWriter( ).println( "ERROR");
			} catch (IOException e) {
				logger.error( e.getMessage( ));
			}
			return this;
		}
	};
	
	private String name;
	
	private static Map< String, XsltStorageOperation> map = new HashMap< String, XsltStorageOperation>( );
	
	protected Logger logger = Logger.getLogger(  XsltStorageOperation.class);
	
	protected ThreadLocal<OperationResult> status = new ThreadLocal<OperationResult>( ) {
		@Override
		protected OperationResult initialValue( ) {
			return OperationResult.SUCCESS;
		}
	};
	
	protected EntityManagerFactory emf = Persistence.createEntityManagerFactory( "jpaProvider");
	
	static {
		for ( XsltStorageOperation $ : XsltStorageOperation.values( )) {
			map.put( $.name, $);
		}
	};
	
	private XsltStorageOperation( String name) {
		this.name = name;
	}
	
	public static XsltStorageOperation fromString( String name) {
		XsltStorageOperation $ = map.get( name);
		if ( null != $)
			return $;
		return UNDEFINED;
	}
	
	@Override
	public String toString( ) {
		return name;
	}
	
	abstract public XsltStorageOperation execute( HttpServletRequest request);
	
	abstract public XsltStorageOperation result( HttpServletResponse response);
}
